package com.allenkerr;

import com.alibaba.fastjson.JSON;
import com.allenkerr.model.Bag;
import com.allenkerr.model.Goddess;
import com.allenkerr.model.Man;
import com.allenkerr.dao.ManRepository;
import com.mongodb.*;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.test.context.junit4.SpringRunner;

import java.text.ParseException;
import java.util.Arrays;
import java.util.List;

import static com.allenkerr.model.Man.dateFormat;

/**
 * Created by 小柯 on 17/6/28.
 */
@RunWith(SpringRunner.class)
@SpringBootTest
public class MongoDbTest03 {

    @Autowired
    private MongoTemplate mongoTemplate;
    @Autowired
    private ManRepository manRepository;

    /**
     * 存
     */
    @Test
    public void test1() throws ParseException {
        Bag b1 = new Bag(11, "爱马仕", new String[]{"黑色", "灰色"});
        Bag b2 = new Bag(12, "LV", new String[]{"枚红色", "粉色"});
        Bag b3 = new Bag(13, "MK", new String[]{"蓝色", "粉色"});

        Goddess g1 = new Goddess(101, "林志玲", 32, b1);
        Goddess g2 = new Goddess(102, "苍老师", 31, b2);
        Goddess g3 = new Goddess(103, "寡姐", 34, b3);

        Man m1 = new Man(1, "张三", g1, dateFormat.parse("1990-01-01"));
        Man m2 = new Man(2, "李四", g2, dateFormat.parse("1991-01-01"));
        Man m3 = new Man(3, "王五", g2, dateFormat.parse("1992-01-01"));
        Man m4 = new Man(4, "赵六", g3, dateFormat.parse("1993-01-01"));
        Man m5 = new Man(5, "田七", g3, dateFormat.parse("1994-01-01"));
        Man m6 = new Man(6, "王霸", g3, dateFormat.parse("1995-01-01"));

        List<Man> men = Arrays.asList(m1, m2, m3, m4, m5, m6);

        mongoTemplate.insertAll(men);
    }

    @Test
    public void testFindInArray() {
//        Query query = Query.query(Criteria.where("goddess.bag.color").in("粉色").nin("蓝色"));

//        Query query = Query.query(new Criteria().andOperator(
//                Criteria.where("goddess.bag.color").in("粉色"),
//                Criteria.where("goddess.bag.color").nin("蓝色")
//        ));

        Query query = Query.query(Criteria.where("goddess.bag.color").in("粉色")
                .andOperator(Criteria.where("goddess.bag.color").nin("蓝色")));

        List<Man> men = mongoTemplate.find(query, Man.class);
        men.forEach(System.out::println);
    }

    @Test
    public void testInOperate() {
//        Query query = Query.query(Criteria.where("goddess.name").in("林志玲", "苍老师"));
//        Query query = Query.query(Criteria.where("goddess.name").nin("林志玲", "苍老师"));
        Query query = Query.query(new Criteria().orOperator(
                Criteria.where("goddess.name").is("林志玲"),
                Criteria.where("goddess.name").is("苍老师")
        ));

        List<Man> men = mongoTemplate.find(query, Man.class);
        men.forEach(System.out::println);
    }

    /**
     * 查
     */
    @Test
    public void test2() {
        Query query = Query.query(Criteria.where("goddess.name").is("苍老师"));
        List<Man> men = mongoTemplate.find(query, Man.class);
        men.forEach(System.out::println);
    }

    /**
     * 用 Criteria 查所有
     */
    @Test
    public void testFindAll() {//TODO for review system
        Criteria criteria = new Criteria();
        Query query = Query.query(criteria);
        List<Man> men = mongoTemplate.find(query, Man.class);
        men.forEach(System.out::println);
    }

    @Test
    public void testFindByPage() {
        Query query = Query.query(new Criteria());
        //分页
        int page = 1;
        int rows = 3;
        query.with(new PageRequest(page - 1, rows, new Sort(Sort.Direction.ASC, "id")));

        List<Man> men = mongoTemplate.find(query, Man.class);
        men.forEach(System.out::println);
    }

    @Test
    public void testFindAllAndShowSomeField() {
        Criteria criteria = new Criteria();
        Query query = Query.query(criteria);
        query.fields().include("name").include("birthday");
        List<Man> men = mongoTemplate.find(query, Man.class);
        men.forEach(System.out::println);
    }

    /**
     * 用 Criteria 拼接查询条件
     */
    @Test
    public void testAnd() {//TODO for review system
        Criteria c1 = Criteria.where("goddess.name").is("苍老师");
        Criteria c2 = Criteria.where("name").is("王五");
        Criteria criteria = new Criteria().andOperator(c1, c2);
        Query query = Query.query(criteria);
        List<Man> men = mongoTemplate.find(query, Man.class);
        men.forEach(System.out::println);
    }

    @Test
    public void test3() {
        Query query = Query.query(Criteria.where("goddess.bag.bagName").is("MK"));
        List<Man> men = mongoTemplate.find(query, Man.class);
        men.forEach(System.out::println);
    }

    @Test
    public void test4() {
//        Query query = Query.query(Criteria.where("goddess.bag.color").in("粉色"));
        Query query = Query.query(Criteria.where("goddess.bag.color").regex("色"));
        List<Man> men = mongoTemplate.find(query, Man.class);
        men.forEach(System.out::println);
    }

    @Test
    public void test5() {
        //Query query = Query.query(Criteria.where("goddess.bag.color").is(new String[]{"粉色", "蓝色"}));
        Query query = Query.query(Criteria.where("goddess.bag.color").is(new String[]{"蓝色", "粉色"}));
        List<Man> men = mongoTemplate.find(query, Man.class);
        men.forEach(System.out::println);
    }

    @Test
    public void test6() {
        Query query = Query.query(Criteria.where("goddess.bag.color").in("粉色"));

        //无效
        /*query.fields().include("goddess.bag.bagId").include("goddess.bag.bagName").include("goddess.bag.color");
        Aggregation aggregation = newAggregation(
                group("goddess.bag.bagId").first("goddess.bag.bagId").as("bagId")
        );
        List<Bag> bags = mongoTemplate.find(query, Bag.class, "men");
        bags.forEach(System.out::println);*/

        Man man = mongoTemplate.findOne(query, Man.class);
        System.out.println("man = " + man);
        Bag bag = man.getGoddess().getBag();
        System.out.println("bag = " + bag);
    }

    @Test
    public void test7() {
        Man man = manRepository.findOne(1);
        System.out.println("man = " + man);
    }

    private static DBCollection col;


    @Before
    public void before() {
        col = mongoTemplate.getCollection("men");
    }

    @Test
    public void test8() {
        BasicDBObject query = new BasicDBObject("goddess.name", "苍老师")
                .append("name", "李四");
        BasicDBObject fields = new BasicDBObject("name", 1)
                .append("_id", 0)
                .append("goddess.name", 1)
                .append("goddess.bag", 1);
        DBCursor dbObjects = col.find(query, fields);
        //dbObjects.forEach(System.out::println);
        dbObjects.forEach(obj -> System.out.println(JSON.toJSONString(obj)));
    }

    @Test
    public void test9() {
        BasicDBObject case1 = new BasicDBObject("goddess.name", "苍老师");
        BasicDBObject case2 = new BasicDBObject("name", "李四");
        BasicDBList basicDBList = new BasicDBList();
        basicDBList.add(case1);
        basicDBList.add(case2);
        BasicDBObject query = new BasicDBObject("$and", basicDBList);

        BasicDBObject fields = new BasicDBObject("name", 1)
                .append("_id", 0)
                .append("goddess.name", 1)
                .append("goddess.bag", 1);

        DBCursor dbObjects = col.find(query, fields);
        dbObjects.forEach(obj -> System.out.println(JSON.toJSONString(obj)));
    }

    /**
     * or
     * 参考：https://stackoverflow.com/questions/10620771/how-can-i-build-an-or-query-for-mongodb-using-the-java-driver
     */
    @Test
    public void test10() {
        BasicDBObject case1 = new BasicDBObject("goddess.name", "苍老师")
                .append("name", "李四");
        BasicDBObject case2 = new BasicDBObject("goddess.name", "林志玲")
                .append("name", "张三");
        BasicDBList basicDBList = new BasicDBList();
        basicDBList.add(case1);
        basicDBList.add(case2);
        BasicDBObject query = new BasicDBObject("$or", basicDBList);//or

        BasicDBObject fields = new BasicDBObject("name", 1)
                .append("_id", 0)
                .append("goddess.name", 1)
                .append("goddess.bag", 1);

        DBCursor dbObjects = col.find(query, fields);
        dbObjects.forEach(obj -> System.out.println(JSON.toJSONString(obj)));
    }

    /**
     * sort
     */
    @Test
    public void test11() {
        BasicDBObject query = new BasicDBObject("name", new BasicDBObject("$ne", "蛋蛋"));    //ne
        BasicDBObject fields = new BasicDBObject("_class", 0);  //不显示 _class

        DBCursor dbObjects = col.find(query, fields);

        int total = dbObjects.count();
        System.out.println("total = " + total);

        dbObjects.sort(new BasicDBObject("_id", -1))
                .skip(2).limit(3)
                .forEach(System.out::println);

        System.out.println("---------------------------------");

        dbObjects.sort(new BasicDBObject("goddess.age", 1))
                .skip(0).limit(total)
                .forEach(System.out::println);
    }

    /**
     * lt, gt
     * https://stackoverflow.com/questions/14314692/how-to-do-this-mongodb-query-using-java
     */
    @Test
    public void test12() {
        BasicDBObject query = new BasicDBObject("goddess.age", new BasicDBObject("$lt", 33));
        DBCursor dbObjects = col.find(query);
        dbObjects.forEach(System.out::println);
    }

    /**
     * lt, gt
     */
    @Test
    public void test13() {
        DBObject query = QueryBuilder.start("goddess.age").greaterThan(33).get();
        col.find(query).forEach(System.out::println);
    }

    /**
     * lt, gt --> date
     */
    @Test
    public void test14() throws ParseException {
        DBObject query = QueryBuilder.start("birthday").greaterThan(dateFormat.parse("1993-01-01")).get();
        col.find(query).forEach(System.out::println);
    }

}
